// locutor
// (c) 2008-2009, Normen Müller, normen.mueller@gmail.com  
// $Id: Lexer.scala 2476 2009-10-05 16:54:16Z nmueller $
package locutor.model.parsing.dep

import scala.util.parsing.combinator._
import scala.util.parsing.combinator.lexical._
import scala.util.parsing.input.CharArrayReader.EofCh

/** 
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.2 */
private [dep] class Lexer extends StdLexical with RegexParsers {
  override type Elem = Char
  
  override def token: Parser[Token] = 
    ( string ^^ StringLit
    | number ^^ NumericLit
    | delim
    | id     ^^ {case i if reserved contains i => Keyword(i) case i => Identifier(i)}  
    | EofCh ^^^ EOF    
    | '\"' ~> failure("Unterminated string")
    | failure("Illegal character")
    )
  
  override def whitespace: Parser[Any] = rep(whitespaceChar | '/' ~ '/' ~ rep(chrExcept(EofCh, '\n')))
  
  def string  = '\"' ~> rep(charSeq | chrExcept('\"', '\n', EofCh)) <~ '\"' ^^ { _ mkString "" }
  
  def number  = """-?(\d+(\.\d*)?|\d*\.\d+)([eE][+-]?\d+)?[fFdD]?""".r
  
  def id      = rep(letter | digit | elem("underscore", _=='_')) ^^ { _ mkString "" }
  
  def charSeq = 
    ( '\\' ~ '\"' ^^^ "\"" | '\\' ~ '\\' ^^^ "\\" | '\\' ~ '/'  ^^^ "/" | '\\' ~ 'b'  ^^^ "\b" | '\\' ~ 'f'  ^^^ "\f" 
    | '\\' ~ 'n'  ^^^ "\n" |'\\' ~ 'r'  ^^^ "\r" |'\\' ~ 't'  ^^^ "\t" |'\\' ~ 'u' ~> unicodeBlock
    )
  
  import scala.io.UTF8Codec.{encode}
  def unicodeBlock = hexDigit ~ hexDigit ~ hexDigit ~ hexDigit ^^ {
    case a ~ b ~ c ~ d => new String(encode(Integer.parseInt(List(a, b, c, d) mkString "", 16)))
  }
  
  val hexDigits = Set[Char]() ++ "0123456789abcdefABCDEF".toArray
  
  def hexDigit = elem("hex digit", hexDigits.contains(_))
}
